package com.zhudoo.zhilian.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zhudoo.zhilian.config.Config;
import com.zhudoo.zhilian.util.web.BusinessException;
import org.apache.tomcat.util.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.*;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;


/**
 * 小程序工具
 *
 * @author
 */
public class MiniProgramUtil {

    private static Logger logger = LoggerFactory.getLogger(MiniProgramUtil.class);

    /**
     * 小程序的accessToken
     */
    private static Map<String, Object> SMALL_PROGRAM_ACCESS_TOKEN_MAP = new HashMap<>(3);

    /**
     * 获取小程序有效的accessToken
     *
     * @return
     */
    public static String getSmallAvailableAccessToken() {
        Long expiresIn = (Long) SMALL_PROGRAM_ACCESS_TOKEN_MAP.get("expires_in");
        //第一次获得token 或者如果当前的时间戳大于token有效时间戳
        if (SMALL_PROGRAM_ACCESS_TOKEN_MAP.isEmpty() || expiresIn <= System.currentTimeMillis()) {
            String url = "https://api.weixin.qq.com/cgi-bin/token" + "?grant_type=client_credential&" + "appid=" + Config.MINIPROGRAM_APPID + "&secret=" + Config.MINIPROGRAM_SECRET;
            logger.info("更新accessToken url={}", url);
            String accessTokenJson = HttpUtil.get(url);
            if (!accessTokenJson.contains("errcode")) {
                JSONObject accessToken = JSON.parseObject(accessTokenJson);
                //更新
                SMALL_PROGRAM_ACCESS_TOKEN_MAP.put("access_token", accessToken.get("access_token"));
                //当前时间加上token的有效时间
                SMALL_PROGRAM_ACCESS_TOKEN_MAP.put("expires_in", System.currentTimeMillis() + (accessToken.getInteger("expires_in") + 60) * 1000);
                logger.info("更新SMALL_PROGRAM_ACCESS_TOKEN_MAP:{}", JSON.toJSON(SMALL_PROGRAM_ACCESS_TOKEN_MAP));
            }
        }
        //获取token
        String accessToken = (String) SMALL_PROGRAM_ACCESS_TOKEN_MAP.get("access_token");
        return accessToken;
    }


    /**
     * 解密数据
     *
     * @return
     * @throws Exception
     */
    public static Map<String, Object> decrypt(String encryptedData, String sessionKey, String iv) {
        try {
            byte[] resultByte = decrypt(Base64.decodeBase64(encryptedData), Base64.decodeBase64(sessionKey), Base64.decodeBase64(iv));
            if (null != resultByte && resultByte.length > 0) {
                String result = new String(PKCS7Encoder.decode(resultByte));
                JSONObject jsonObject = JSON.parseObject(result);
                return jsonObject;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        throw BusinessException.getInstance("微信授权失败");
    }

    public static boolean initialized = false;

    /**
     * AES解密
     *
     * @param content 密文
     * @return
     * @throws InvalidAlgorithmParameterException
     * @throws NoSuchProviderException
     */
    public static byte[] decrypt(byte[] content, byte[] keyByte, byte[] ivByte) {
        initialize();
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
            Key sKeySpec = new SecretKeySpec(keyByte, "AES");
            // 初始化
            cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIV(ivByte));
            byte[] result = cipher.doFinal(content);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void initialize() {
        if (initialized) {
            return;
        }
        Security.addProvider(new BouncyCastleProvider());
        initialized = true;
    }

    /**
     * 生成iv
     *
     * @param iv
     * @return
     * @throws Exception
     */
    public static AlgorithmParameters generateIV(byte[] iv) throws Exception {
        AlgorithmParameters params = AlgorithmParameters.getInstance("AES");
        params.init(new IvParameterSpec(iv));
        return params;
    }

    public static String JSCODE2SESSION = " https://api.weixin.qq.com/sns/jscode2session?appid={0}&secret={1}&js_code={2}&grant_type=authorization_code";

    /**
     * 获取小程序
     *
     * @param code
     * @return
     */
    public static Map<String, Object> miniProgramLogin(String code) {
        String jsCode2SeesionUrl = MessageFormat.format(JSCODE2SESSION, Config.MINIPROGRAM_APPID, Config.MINIPROGRAM_SECRET, code);
        String jsonResult = HttpUtil.get(jsCode2SeesionUrl);
        Map<String, Object> accessOpenIdResult = JSON.parseObject(jsonResult, Map.class);
        return accessOpenIdResult;
         /*{
                "openid":" OPENID",
                "session_key": "SESSIONKEY",
			    "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
		}
		*/
    }


    /**
     * 发送小程序消息
     *
     * @param openId
     * @param templateId
     * @param page
     * @param dataMap
     */
    public static void sendMiniProgramMessage(String openId, String templateId, String page, String formId, Map dataMap) {
        Map<String, Object> paramMap = new HashMap<>(5);
        paramMap.put("touser", openId);
        paramMap.put("template_id", templateId);
        if (StringUtils.isNotEmpty(page)) {
            paramMap.put("page", page);
        }
        paramMap.put("form_id", formId);
        paramMap.put("data", dataMap);
        HttpUtil.post(MessageFormat.format("https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token={0}", getSmallAvailableAccessToken()), JSON.toJSONString(paramMap));
    }

}